using System;
using System.Collections.Generic;
using System.Runtime.Serialization;


namespace MonsterNet
{
	/// <summary>
	/// Contains contents to be loaded and saved by the controller class. 
	/// Everything in here has to be binary serialisable
	/// </summary>
	[Serializable]
	public class MNPersisted : ISerializable {
		private int kNumberOfScansToKeep = 10;
		
		public List<string> ExtensionsToIgnore;
		public MNSynchronisedDirectory Root;
		private SerializableDictionary<DateTime, MNFSObjectLocation> _scans;
		
		private DateTime[] _lastScans;
		
		public MNPersisted() {
			ExtensionsToIgnore = new List<string>();
			Root = new MNSynchronisedDirectory(MNSynchronisedDirectory.kRootSyncDirectory);
			_scans = new SerializableDictionary<DateTime, MNFSObjectLocation>();
			_lastScans = new DateTime[(int)MNFSObjectLocation.NumberOfLocations];
		}
		
		public DateTime LastScanForLocation(MNFSObjectLocation location) {
			if(_lastScans[(int)location] == new DateTime()) {
				_lastScans[(int)location] = GetLastScanForLocation(location);
			}
			
			return _lastScans[(int)location];
		}
		
		public void SetLastScanForLocation(DateTime scanDate, MNFSObjectLocation location) {
			_scans.Add(scanDate, location);
			_lastScans[(int)location] = scanDate;
			DeleteOldestScanForLocation(location);
		}
		
		/// <summary>
		/// Set up events handlers for file/directory updating.
		/// </summary>
		public void SetUpEvents() {
			Root.SubscribeToChildEvents();
		}
				
		private DateTime GetLastScanForLocation(MNFSObjectLocation location) {
			//loop trough scans until a scan is found for the given location
			DateTime result = new DateTime();
			foreach (KeyValuePair<DateTime, MNFSObjectLocation> kvp in _scans) {
				if(kvp.Value == location && result < kvp.Key) {					
					result = kvp.Key;
				}
			}
			return result;	
		}
		
		/// <summary>
		/// Delete scanning history beyond the last kNumberOfScansToKeep
		/// </summary>
		/// <param name="location">
		/// A <see cref="MNFSObjectLocation"/> 
		/// </param>
		private void DeleteOldestScanForLocation(MNFSObjectLocation location) {
			
			int numberOfScansAtLocation = 0;
			DateTime oldest = DateTime.Now;
			foreach (KeyValuePair<DateTime, MNFSObjectLocation> kvp in _scans) {
				if(kvp.Value == location) {
					numberOfScansAtLocation++;
					if(kvp.Key < oldest) {
						oldest = kvp.Key;
					}
				}
			}
			
			if(numberOfScansAtLocation > kNumberOfScansToKeep && _scans.ContainsKey(oldest)) {
				_scans.Remove(oldest);
			}
		}
		
		#region Serialization
		
		public MNPersisted(SerializationInfo info, StreamingContext ctxt) {	
			
			ExtensionsToIgnore = new List<string>();
			int itemCount = info.GetInt32("ExtensionsToIgnoreCount");
			for (int i = 0; i < itemCount; i++)
			{
				string ext =  info.GetString(string.Format(@"Ext{0}", i));
				ExtensionsToIgnore.Add(ext);
			}		
			
			Root = (MNSynchronisedDirectory)info.GetValue(@"Root", typeof(MNSynchronisedDirectory));	
			_scans = (SerializableDictionary<DateTime, MNFSObjectLocation>)info.GetValue(@"scans",typeof(SerializableDictionary<DateTime, MNFSObjectLocation>));
			_lastScans = new DateTime[(int)MNFSObjectLocation.NumberOfLocations];
		}
		
		public void GetObjectData(SerializationInfo info, StreamingContext ctxt) {
			
			info.AddValue("ExtensionsToIgnoreCount", ExtensionsToIgnore.Count);
			int i = 0;
			foreach (string ext in ExtensionsToIgnore)
			{
				info.AddValue(string.Format(@"Ext{0}", i), ext, typeof(string));
				i++;
			}			
			info.AddValue(@"Root", Root, typeof(MNSynchronisedDirectory));
			info.AddValue(@"scans", _scans);		
		}		
		
		#endregion		
	}
}

